
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
  <meta charset="utf-8">
  <title>编写高质量代码(上) - Yebangyu's Blog</title>
  <meta name="author" content="Yebangyu">

  
  <meta name="description" content="本文介绍如何编写高质量的C++代码。从代码规范、软件工程、算法设计等角度综合讲解">
  <meta name="keywords" content="C++, 代码规范, 重构, 设计, 正确性, 算法">

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  
  <link rel="canonical" href="http://www.yebangyu.org/blog/2015/11/06/how-to-write-elegant-cpp-codes/">
  <link href="/favicon.png" rel="icon">
  <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
  <link href="/atom.xml" rel="alternate" title="Yebangyu's Blog" type="application/atom+xml">
  <script src="/javascripts/modernizr-2.0.js"></script>
  <script src="//ajax.lug.ustc.edu.cn/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script>!window.jQuery && document.write(unescape('%3Cscript src="/javascripts/libs/jquery.min.js"%3E%3C/script%3E'))</script>
  <script src="/javascripts/octopress.js" type="text/javascript"></script>
  <!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>

  

</head>

<body   >
  <header role="banner"><hgroup>
  <h1><a href="/">Yebangyu's Blog</a></h1>
  
    <h2>Fond of Concurrency Programming and Machine Learning</h2>
  
</hgroup>

</header>
  <nav role="navigation"><ul class="subscription" data-subscription="rss">
  <li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
  
</ul>
  
<form action="https://www.google.com/search" method="get">
  <fieldset role="search">
    <input type="hidden" name="sitesearch" value="www.yebangyu.org">
    <input class="search" type="text" name="q" results="0" placeholder="Search"/>
  </fieldset>
</form>
  
<ul class="main-navigation">
  <li><a href="/">Blog</a></li>
  <li><a href="/blog/archives">Archives</a></li>
  <li><a href="/about">About Me</a></li>
</ul>

</nav>
  <div id="main">
    <div id="content">
      <div>
<article class="hentry" role="article">
  
  <header>
    
      <h1 class="entry-title">编写高质量代码(上)</h1>
    
    
      <p class="meta">
        




<time class='entry-date' datetime='2015-11-06T00:24:56+08:00'><span class='date'><span class='date-month'>Nov</span> <span class='date-day'>6</span><span class='date-suffix'>th</span>, <span class='date-year'>2015</span></span> <span class='time'>12:24 am</span></time>
        
      </p>
    
  </header>


<div class="entry-content"><p>我们知道，<strong>int</strong>和<strong>double</strong>能表示的数值的范围不同。其中，<strong>64</strong>位有符号整数的范围是[<strong>-9223372036854775808</strong>,<strong>9223372036854775807</strong>]，而<strong>64</strong>位无符号整数的范围是[<strong>0</strong>,<strong>18446744073709551615</strong>]。这两个区间有一定的<strong>overlap</strong>，而<strong>double</strong>可以表示的范围更大。</p>

<p>现在，需要编写两个函数:给定一个<strong>double</strong>型的<strong>value</strong>，判断这个<strong>value</strong>是否是一个合法的<strong>int64_t</strong>或者<strong>uint64_t</strong>。本文说的“合法”，是指数值上落在了范围内。</p>

<pre><code>bool is_valid_uint64(const Double &amp;value);

bool is_valid_int64(const Double &amp;value);
</code></pre>

<p>这里我们用<strong>Double</strong>而不是<strong>double</strong>，原因是我们的<strong>double</strong>不是基础数据类型，而是通过一定方法实现的<strong>ADT</strong>，这个<strong>ADT</strong>的成员函数有：</p>

<!--more-->

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="k">class</span> <span class="nc">Double</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">public</span><span class="o">:</span>
</span><span class="line">    <span class="kt">int</span> <span class="n">get_next_digit</span><span class="p">(</span><span class="kt">bool</span> <span class="o">&amp;</span><span class="n">is_decimal</span><span class="p">);</span>
</span><span class="line">    <span class="kt">bool</span> <span class="nf">is_zero</span><span class="p">();</span>
</span><span class="line">    <span class="kt">bool</span> <span class="nf">is_neg</span><span class="p">();</span>
</span><span class="line"><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>通过调用<code>get_next_digit</code>，可以返回一个数字，不断调用它，可以得到所有<strong>digits</strong>。举个例子，对于值为<strong>45.67</strong>的一个<strong>Double</strong>对象，调用它的<code>get_next_digit</code>成员函数将依次得到</p>

<p>4 is_decimal = false //表示整数部分</p>

<p>5 is_decimal = false //表示整数部分</p>

<p>6 is_decimal = true //表示小数部分</p>

<p>7 is_decimal = true //表示小数部分</p>

<p>当<code>get_next_digit</code>返回<strong>-1</strong>时，表示读取完毕。</p>

<p>如何利用<strong>Double</strong>类里的成员函数，来实现<code>is_valid_uint64</code>和<code>is_valid_int64</code>这两个函数呢？</p>

<p>一些新手可能会写这样的代码：</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
<span class="line-number">27</span>
<span class="line-number">28</span>
<span class="line-number">29</span>
<span class="line-number">30</span>
<span class="line-number">31</span>
<span class="line-number">32</span>
<span class="line-number">33</span>
<span class="line-number">34</span>
<span class="line-number">35</span>
<span class="line-number">36</span>
<span class="line-number">37</span>
<span class="line-number">38</span>
<span class="line-number">39</span>
<span class="line-number">40</span>
<span class="line-number">41</span>
<span class="line-number">42</span>
<span class="line-number">43</span>
<span class="line-number">44</span>
<span class="line-number">45</span>
<span class="line-number">46</span>
<span class="line-number">47</span>
<span class="line-number">48</span>
<span class="line-number">49</span>
<span class="line-number">50</span>
<span class="line-number">51</span>
<span class="line-number">52</span>
<span class="line-number">53</span>
<span class="line-number">54</span>
<span class="line-number">55</span>
<span class="line-number">56</span>
<span class="line-number">57</span>
<span class="line-number">58</span>
<span class="line-number">59</span>
<span class="line-number">60</span>
<span class="line-number">61</span>
<span class="line-number">62</span>
<span class="line-number">63</span>
<span class="line-number">64</span>
<span class="line-number">65</span>
<span class="line-number">66</span>
<span class="line-number">67</span>
<span class="line-number">68</span>
<span class="line-number">69</span>
<span class="line-number">70</span>
<span class="line-number">71</span>
<span class="line-number">72</span>
<span class="line-number">73</span>
<span class="line-number">74</span>
<span class="line-number">75</span>
<span class="line-number">76</span>
<span class="line-number">77</span>
<span class="line-number">78</span>
<span class="line-number">79</span>
<span class="line-number">80</span>
<span class="line-number">81</span>
<span class="line-number">82</span>
<span class="line-number">83</span>
<span class="line-number">84</span>
<span class="line-number">85</span>
<span class="line-number">86</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="kt">bool</span> <span class="nf">is_valid_uint64</span><span class="p">(</span><span class="k">const</span> <span class="n">Double</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">bool</span> <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">digits</span><span class="p">[</span><span class="mi">2000</span><span class="p">];</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">counts</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">is_zero</span><span class="p">())</span> <span class="p">{</span>
</span><span class="line">    <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">is_neg</span><span class="p">())</span> <span class="p">{</span>
</span><span class="line">    <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">    <span class="kt">bool</span> <span class="n">is_decimal</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">    <span class="kt">int</span> <span class="n">digit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">    <span class="k">while</span><span class="p">((</span><span class="n">digit</span><span class="o">=</span><span class="n">value</span><span class="p">.</span><span class="n">get_next_digit</span><span class="p">(</span><span class="n">is_decimal</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="k">if</span> <span class="p">(</span><span class="n">is_decimal</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">        <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">        <span class="k">break</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">        <span class="n">digits</span><span class="p">[</span><span class="n">counts</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">digit</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">tmp</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class="line">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">counts</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="n">tmp</span> <span class="o">+=</span> <span class="n">digits</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">base</span><span class="p">;</span>
</span><span class="line">      <span class="k">if</span> <span class="p">(</span><span class="n">tmp</span> <span class="o">&gt;</span> <span class="n">UINT64_MAX</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">        <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">        <span class="k">break</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span>
</span><span class="line">      <span class="n">base</span> <span class="o">*=</span> <span class="mi">10</span><span class="p">;</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">return</span> <span class="n">is_valid</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">bool</span> <span class="nf">is_valid_int64</span><span class="p">(</span><span class="k">const</span> <span class="n">Double</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="kt">bool</span> <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">digits</span><span class="p">[</span><span class="mi">2000</span><span class="p">];</span>
</span><span class="line">  <span class="kt">int</span> <span class="n">counts</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">is_zero</span><span class="p">())</span> <span class="p">{</span>
</span><span class="line">    <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span><span class="line">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">is_neg</span><span class="p">())</span> <span class="p">{</span>
</span><span class="line">    <span class="kt">bool</span> <span class="n">is_decimal</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">    <span class="kt">int</span> <span class="n">digit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">    <span class="k">while</span><span class="p">((</span><span class="n">digit</span><span class="o">=</span><span class="n">value</span><span class="p">.</span><span class="n">get_next_digit</span><span class="p">(</span><span class="n">is_decimal</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="k">if</span> <span class="p">(</span><span class="n">is_decimal</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">        <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">        <span class="k">break</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">        <span class="n">digits</span><span class="p">[</span><span class="n">counts</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">digit</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">tmp</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class="line">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">counts</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="n">tmp</span> <span class="o">+=</span> <span class="n">digits</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">base</span><span class="p">;</span>
</span><span class="line">      <span class="n">tmp</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span><span class="line">      <span class="k">if</span> <span class="p">(</span><span class="n">tmp</span> <span class="o">&lt;</span> <span class="n">INT64_MIN</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">        <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">        <span class="k">break</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span>
</span><span class="line">      <span class="n">base</span> <span class="o">*=</span> <span class="mi">10</span><span class="p">;</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">    <span class="kt">bool</span> <span class="n">is_decimal</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">    <span class="kt">int</span> <span class="n">digit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">    <span class="k">while</span><span class="p">((</span><span class="n">digit</span><span class="o">=</span><span class="n">value</span><span class="p">.</span><span class="n">get_next_digit</span><span class="p">(</span><span class="n">is_decimal</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="k">if</span> <span class="p">(</span><span class="n">is_decimal</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">        <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">        <span class="k">break</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">        <span class="n">digits</span><span class="p">[</span><span class="n">counts</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">digit</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">tmp</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class="line">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">counts</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="n">tmp</span> <span class="o">+=</span> <span class="n">digits</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">base</span><span class="p">;</span>
</span><span class="line">      <span class="k">if</span> <span class="p">(</span><span class="n">tmp</span> <span class="o">&gt;</span> <span class="n">INT64_MAX</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">        <span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">        <span class="k">break</span><span class="p">;</span>
</span><span class="line">      <span class="p">}</span>
</span><span class="line">      <span class="n">base</span> <span class="o">*=</span> <span class="mi">10</span><span class="p">;</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">return</span> <span class="n">is_valid</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>这样的代码，存在诸多问题。</p>

<h2 id="section">设计问题</h2>

<p>不难发现，两个函数存在很多相似甚至相同的代码；而同一个函数内部，也有不少代码重复。重复的东西往往不是好的。重构？</p>

<h2 id="section-1">性能问题</h2>

<p>先获得所有digits，然后从最低位开始向最高位构造值，效率较低。难道没有可以从最高位开始，边获得边计算，不需要临时数组存储所有digits的方法吗？</p>

<h2 id="section-2">正确性问题</h2>

<p>随便举几个例子：</p>

<p>第<strong>24</strong>行，<code>tmp += digits[i] * base</code>;有没有考虑到可能的溢出呢？</p>

<p>第<strong>68</strong>行，难道有小数部分就一定不是合法的<strong>int64</strong>吗？那么，<strong>123.000</strong>？嗯？</p>

<h2 id="section-3">规范问题</h2>

<p>帅哥，这么多代码，一行注释都没有，这样真的好吗？</p>

<p>因此，毫无疑问，这是烂代码，不合格的代码，需要重写的代码。</p>

<hr />

<p>以下是我个人认为比较好的设计和实现，仅供参考。</p>

<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
<span class="line-number">27</span>
<span class="line-number">28</span>
<span class="line-number">29</span>
<span class="line-number">30</span>
<span class="line-number">31</span>
<span class="line-number">32</span>
<span class="line-number">33</span>
<span class="line-number">34</span>
<span class="line-number">35</span>
<span class="line-number">36</span>
<span class="line-number">37</span>
<span class="line-number">38</span>
<span class="line-number">39</span>
<span class="line-number">40</span>
<span class="line-number">41</span>
<span class="line-number">42</span>
<span class="line-number">43</span>
<span class="line-number">44</span>
<span class="line-number">45</span>
<span class="line-number">46</span>
<span class="line-number">47</span>
<span class="line-number">48</span>
<span class="line-number">49</span>
<span class="line-number">50</span>
<span class="line-number">51</span>
<span class="line-number">52</span>
<span class="line-number">53</span>
<span class="line-number">54</span>
<span class="line-number">55</span>
<span class="line-number">56</span>
<span class="line-number">57</span>
<span class="line-number">58</span>
<span class="line-number">59</span>
<span class="line-number">60</span>
<span class="line-number">61</span>
<span class="line-number">62</span>
<span class="line-number">63</span>
<span class="line-number">64</span>
<span class="line-number">65</span>
<span class="line-number">66</span>
<span class="line-number">67</span>
<span class="line-number">68</span>
<span class="line-number">69</span>
<span class="line-number">70</span>
<span class="line-number">71</span>
<span class="line-number">72</span>
<span class="line-number">73</span>
<span class="line-number">74</span>
<span class="line-number">75</span>
<span class="line-number">76</span>
<span class="line-number">77</span>
<span class="line-number">78</span>
<span class="line-number">79</span>
<span class="line-number">80</span>
<span class="line-number">81</span>
<span class="line-number">82</span>
<span class="line-number">83</span>
<span class="line-number">84</span>
<span class="line-number">85</span>
<span class="line-number">86</span>
<span class="line-number">87</span>
<span class="line-number">88</span>
<span class="line-number">89</span>
<span class="line-number">90</span>
<span class="line-number">91</span>
<span class="line-number">92</span>
<span class="line-number">93</span>
<span class="line-number">94</span>
<span class="line-number">95</span>
<span class="line-number">96</span>
<span class="line-number">97</span>
<span class="line-number">98</span>
<span class="line-number">99</span>
<span class="line-number">100</span>
<span class="line-number">101</span>
<span class="line-number">102</span>
<span class="line-number">103</span>
<span class="line-number">104</span>
<span class="line-number">105</span>
<span class="line-number">106</span>
<span class="line-number">107</span>
<span class="line-number">108</span>
<span class="line-number">109</span>
<span class="line-number">110</span>
<span class="line-number">111</span>
<span class="line-number">112</span>
<span class="line-number">113</span>
<span class="line-number">114</span>
<span class="line-number">115</span>
<span class="line-number">116</span>
<span class="line-number">117</span>
<span class="line-number">118</span>
<span class="line-number">119</span>
<span class="line-number">120</span>
<span class="line-number">121</span>
<span class="line-number">122</span>
<span class="line-number">123</span>
<span class="line-number">124</span>
<span class="line-number">125</span>
<span class="line-number">126</span>
<span class="line-number">127</span>
<span class="line-number">128</span>
<span class="line-number">129</span>
<span class="line-number">130</span>
<span class="line-number">131</span>
<span class="line-number">132</span>
<span class="line-number">133</span>
<span class="line-number">134</span>
<span class="line-number">135</span>
<span class="line-number">136</span>
<span class="line-number">137</span>
<span class="line-number">138</span>
<span class="line-number">139</span>
<span class="line-number">140</span>
<span class="line-number">141</span>
<span class="line-number">142</span>
<span class="line-number">143</span>
<span class="line-number">144</span>
<span class="line-number">145</span>
<span class="line-number">146</span>
<span class="line-number">147</span>
<span class="line-number">148</span>
<span class="line-number">149</span>
<span class="line-number">150</span>
<span class="line-number">151</span>
<span class="line-number">152</span>
<span class="line-number">153</span>
<span class="line-number">154</span>
<span class="line-number">155</span>
<span class="line-number">156</span>
<span class="line-number">157</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="kt">bool</span> <span class="nf">is_valid_uint64</span><span class="p">(</span><span class="k">const</span> <span class="n">Double</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span>
</span><span class="line">
</span><span class="line"><span class="p">{</span>
</span><span class="line">
</span><span class="line">  <span class="kt">bool</span> <span class="n">ret</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="n">check_range</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ret</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class="line">
</span><span class="line">  <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span><span class="line">
</span><span class="line"><span class="p">}</span>
</span><span class="line">
</span><span class="line">
</span><span class="line">
</span><span class="line"><span class="kt">bool</span> <span class="nf">is_valid_int64</span><span class="p">(</span><span class="k">const</span> <span class="n">Double</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">)</span>
</span><span class="line">
</span><span class="line"><span class="p">{</span>
</span><span class="line">
</span><span class="line">  <span class="kt">bool</span> <span class="n">ret</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="n">check_range</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ret</span><span class="p">);</span>
</span><span class="line">
</span><span class="line">  <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span><span class="line">
</span><span class="line"><span class="p">}</span>
</span><span class="line">
</span><span class="line">
</span><span class="line">
</span><span class="line"><span class="kt">void</span> <span class="n">check_range</span><span class="p">(</span><span class="k">const</span> <span class="n">Double</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">,</span>
</span><span class="line">
</span><span class="line">                 <span class="kt">bool</span> <span class="o">*</span><span class="n">is_valid_uint64</span><span class="p">,</span>
</span><span class="line">
</span><span class="line">                 <span class="kt">bool</span> <span class="o">*</span><span class="n">is_valid_int64</span><span class="p">)</span> <span class="k">const</span>
</span><span class="line">
</span><span class="line"><span class="p">{</span>
</span><span class="line">
</span><span class="line">  <span class="cm">/*</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 对于一个负数的value，它不可能是一个合法的uint64.</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 因此，只剩下三种可能：</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * I 输入的value是负数，判断是否是合法的int64</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * II 输入的value是正数，判断是否是合法的uint64</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * III 输入的value是正数，判断是否是合法的int64</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 对于第II、III这两种情况：只要判断value的值是否超过uint64、int64的上界即可</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 对于第I种情况，我们利用-A &gt; -B 等价于 A &lt; B （其中A、B是正数）</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 因此，在第I种情况里，可以判断value的绝对值，是否超过int64的最小值的绝对值即可。</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * （int64的最小值的绝对值？那不就是int64的最大值？哦，不！）</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 因此，不管哪种情况，判断绝对值是否超过某个上界即可。</span>
</span><span class="line">
</span><span class="line"><span class="cm">   * 这三种情况，上界不一样。把三个上界存到了一个二维数组THRESHOLD里</span>
</span><span class="line">
</span><span class="line"><span class="cm">  */</span>
</span><span class="line">
</span><span class="line">
</span><span class="line">
</span><span class="line">  <span class="kt">bool</span> <span class="o">*</span><span class="n">is_valid</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">FLAG_INT64</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">FLAG_UINT64</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">SIGN_NEG</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="k">static</span> <span class="k">const</span> <span class="kt">int</span> <span class="n">SIGN_POS</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="kt">int</span> <span class="n">flag</span> <span class="o">=</span> <span class="n">FLAG_INT64</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">!=</span> <span class="n">is_valid_uint64</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">    <span class="n">is_valid</span> <span class="o">=</span> <span class="n">is_valid_uint64</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">    <span class="n">flag</span> <span class="o">=</span> <span class="n">FLAG_UINT64</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">    <span class="n">is_valid</span> <span class="o">=</span> <span class="n">is_valid_int64</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="p">}</span>
</span><span class="line">
</span><span class="line">  <span class="o">*</span><span class="n">is_valid</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">is_zero</span><span class="p">())</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">    <span class="c1">//do nothing。0是合法的uint64，也是合法的int64</span>
</span><span class="line">
</span><span class="line">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">    <span class="kt">int</span> <span class="n">sign</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="n">is_neg</span><span class="p">()</span> <span class="o">?</span> <span class="nl">SIGN_NEG</span> <span class="p">:</span> <span class="n">SIGN_POS</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">    <span class="k">if</span> <span class="p">((</span><span class="n">SIGN_NEG</span> <span class="o">==</span> <span class="n">sign</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">FLAG_UINT64</span> <span class="o">==</span> <span class="n">flag</span><span class="p">))</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">      <span class="o">*</span><span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span><span class="c1">//负数不可能是合法的uint64</span>
</span><span class="line">
</span><span class="line">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">      <span class="kt">uint64_t</span> <span class="n">valueUint</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">      <span class="k">static</span> <span class="kt">uint64_t</span> <span class="n">ABS_INT64_MIN</span> <span class="o">=</span> <span class="mi">9223372036854775808ULL</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">                                         <span class="c1">//int64        uint64</span>
</span><span class="line">
</span><span class="line">      <span class="k">static</span> <span class="kt">uint64_t</span> <span class="n">THRESHOLD</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="n">ABS_INT64_MIN</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="c1">//neg</span>
</span><span class="line">
</span><span class="line">                                         <span class="p">{</span><span class="n">INT64_MAX</span><span class="p">,</span>     <span class="n">UINT64_MAX</span><span class="p">}</span> <span class="p">};</span> <span class="c1">//pos</span>
</span><span class="line">
</span><span class="line">      <span class="kt">int</span> <span class="n">digit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">      <span class="kt">bool</span> <span class="n">is_decimal</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">      <span class="k">while</span> <span class="p">((</span><span class="n">digit</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="n">get_next_digit</span><span class="p">(</span><span class="n">is_decimal</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">is_decimal</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">          <span class="c1">//为了防止溢出，我们不能这么写:</span>
</span><span class="line">
</span><span class="line">          <span class="c1">//&quot;value * 10 + digit &gt; THRESHOLD[index]&quot;</span>
</span><span class="line">
</span><span class="line">          <span class="k">if</span> <span class="p">(</span><span class="n">valueUint</span> <span class="o">&gt;</span> <span class="p">(</span><span class="n">THRESHOLD</span><span class="p">[</span><span class="n">sign</span><span class="p">][</span><span class="n">flag</span><span class="p">]</span> <span class="o">-</span> <span class="n">digit</span><span class="p">)</span> <span class="o">/</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">            <span class="o">*</span><span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">            <span class="k">break</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">          <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">            <span class="n">valueUint</span> <span class="o">=</span> <span class="n">valueUint</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="n">digit</span><span class="p">;</span><span class="c1">//霍纳法则（也叫秦九韶算法）</span>
</span><span class="line">
</span><span class="line">          <span class="p">}</span>
</span><span class="line">
</span><span class="line">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">          <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">digit</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">
</span><span class="line">            <span class="o">*</span><span class="n">is_valid</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">//小数部分必须是0；否则不可能是合法的uint64、int64</span>
</span><span class="line">
</span><span class="line">            <span class="k">break</span><span class="p">;</span>
</span><span class="line">
</span><span class="line">          <span class="p">}</span>
</span><span class="line">
</span><span class="line">        <span class="p">}</span>
</span><span class="line">
</span><span class="line">      <span class="p">}</span>
</span><span class="line">
</span><span class="line">    <span class="p">}</span>
</span><span class="line">
</span><span class="line">  <span class="p">}</span>
</span><span class="line">
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

<h2 id="section-4">致谢</h2>

<p>本文发出后，微博网友@随风巽命 指出了其中一个笔误。非常感谢。</p>

</div>


  <footer>
    <p class="meta">
      
  

<span class="byline author vcard">Posted by <span class="fn">Yebangyu</span></span>

      




<time class='entry-date' datetime='2015-11-06T00:24:56+08:00'><span class='date'><span class='date-month'>Nov</span> <span class='date-day'>6</span><span class='date-suffix'>th</span>, <span class='date-year'>2015</span></span> <span class='time'>12:24 am</span></time>
      

<span class="categories">
  
    <a class='category' href='/blog/categories/c-plus-plus/'>c++</a>
  
</span>


    </p>
    
      <div class="sharing">
  
  
  
</div>

    
    <p class="meta">
      
        <a class="basic-alignment left" href="/blog/2015/10/31/linux-parallen-programmming-infrastructure/" title="Previous Post: Linux环境多线程编程基础设施">&laquo; Linux环境多线程编程基础设施</a>
      
      
        <a class="basic-alignment right" href="/blog/2015/11/06/null-pointer-can-be-accessed/" title="Next Post: 空指针(NULL)不能用吗？">空指针(NULL)不能用吗？ &raquo;</a>
      
    </p>
  </footer>
</article>


</div>

<aside class="sidebar">
  
    <section>
  <h1>Recent Posts</h1>
  <ul id="recent_posts">
    
      <li class="post">
        <a href="/blog/2017/03/11/2017/">2017技术成长之路</a>
      </li>
    
      <li class="post">
        <a href="/blog/2017/02/17/virtualfunctionandvariadicparametertemplate/">虚函数和变长参数模板的妙用</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/25/singleton/">Singleton与多线程</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/04/introductiontohazardpointer/">Lock Free中的Hazard Pointer(下)</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/03/gccandperfopt/">性能优化的那些传说和迷思</a>
      </li>
    
  </ul>
</section>
<section>
  <h1>Friends' Link</h1>
  <ul>
    <li>
	  <li><a href="http://www.chongh.wiki/">Diting0x</a></li>
	  <li><a href="http://www.xiaolili.net/">wangli</a></li>
	  <li><a href="http://www.skykewei.top">dukewei</a></li>
	  <li><a href="http://irwenqiang.github.io">chenwenqiang</a></li>
      <li><a href="http://www.armsword.com">duruofei</a></li>
    </li>
  </ul>
</section><section>
  <h1>Yebangyu</h1>
  <p>福建人。热爱历史、K歌、NBA</p>
  <p>帝都码农</p>
  <p>历史学家，专治秦汉史</p>
</section>
<section>
 <h1>Categories</h1>
 <ul id="categories">
  <li class='category'><a href='/blog/categories/c-plus-plus/'>c++ (11)</a></li>
<li class='category'><a href='/blog/categories/soupen/'>soupen (4)</a></li>
<li class='category'><a href='/blog/categories/web/'>web (1)</a></li>
<li class='category'><a href='/blog/categories/qi-ta/'>其他 (5)</a></li>
<li class='category'><a href='/blog/categories/li-shi/'>历史 (2)</a></li>
<li class='category'><a href='/blog/categories/bing-xing-bian-cheng/'>并行编程 (20)</a></li>
<li class='category'><a href='/blog/categories/xing-neng-you-hua/'>性能优化 (2)</a></li>
<li class='category'><a href='/blog/categories/suan-fa/'>算法 (4)</a></li>
<li class='category'><a href='/blog/categories/bian-yi-lian-jie/'>编译链接 (2)</a></li>

 </ul>
</section>




  
</aside>


    </div>
  </div>
  <footer role="contentinfo"><!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>
<p>
  Copyright &copy; 2017 - Yebangyu -
  <span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1257548193'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s11.cnzz.com/z_stat.php%3Fid%3D1257548193' type='text/javascript'%3E%3C/script%3E"));</script>

</footer>
  











</body>
</html>
